﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Common;
using System.Data.SqlClient;
using System.Diagnostics;
using System.Linq;
using System.Text;

namespace WW.NActiveRecord.Internal
{
    /// <summary>
    /// 对System.Diagnostics.Debug的扩展 
    /// </summary>
    public static class Debug2 {

        public static void PrintAssemblyResourceNames(Type type){
            string[] names = type.Assembly.GetManifestResourceNames();
            for (int i = 0; i < names.Length; i++){
                Debug.WriteLine(names[i]);
            }
        }

        
        /// <summary>
        /// 替换所有的@parameter为参数值,
        /// select * form table where id=1比
        /// select * form table where id=@id更易读些 
        /// </summary>
        /// <param name="command"></param>
        /// <returns></returns>
        public static String FormatCommand(DbCommand command) {
            String result = command.CommandText;


            for (int i = 0; i < command.Parameters.Count; i++) {
                DbParameter param = command.Parameters[i];
                string parameterName = param.ParameterName.StartsWith("@") ? param.ParameterName : "@" + param.ParameterName;
                object paramValue = param.Value;
                if (paramValue is string) {
                    paramValue = "'" + paramValue + "'";
                }
                if(paramValue ==null ){
                    paramValue =  "NULL";
                }
                result = result.Replace(parameterName, paramValue.ToString());
            }
            return result;
        }

        public static void Print(object self){
            Debug.WriteLine(self ?? "null");
        }

        /// <summary>
        /// 按表格格式打印DataTable,可用在调试和控制台程序
        /// </summary>
        /// <param name="table"></param>
        public static void Print(DataTable table){
            List<List<string>> result = new List<List<string>>();

            //列名作为第1行
            List<string> columnNames = new List<string>();
            //列类型作为第2行
            List<string> columnTypes = new List<string>();
            for (int i = 0; i < table.Columns.Count; i++)
            {
                System.Data.DataColumn column = table.Columns[i];
                columnNames.Add(column.ColumnName);
                columnTypes.Add(column.DataType.Name);
            }
            result.Add(columnNames);
            result.Add(columnTypes);

            //遍历表中的所有数据行
            for (int i = 0; i < table.Rows.Count; i++)
            {
                List<string> row = new List<string>();
                object[] items = table.Rows[i].ItemArray;
                for (int j = 0; j < items.Length; j++)
                {
                    row.Add(items[j].ToString());
                }
                result.Add(row);
            }

            //计算每列最大长度
            Dictionary<int, int> maxLength = new Dictionary<int, int>();
            for (int i = 0; i < result.Count; i++)
            {
                List<string> row = result[i];
                for (int j = 0; j < row.Count; j++)
                {
                    int itemLength = GetLength(row[j]);
                    if (!maxLength.ContainsKey(j))
                    {
                        maxLength[j] = itemLength;
                    }
                    else
                    {
                        maxLength[j] = maxLength[j] > itemLength ? maxLength[j] : itemLength;
                    }
                }
            }

            //Print
            for (int i = 0; i < result.Count; i++)
            {
                List<string> row = result[i];
                int space = 2;
                if (i == 2)
                {
                    int t = 0;
                    for (int j = 0; j < row.Count; j++)
                    {
                        t += PadRight(row[j], maxLength[j] + space + 1).Length;
                    }
                    Debug.WriteLine(new string('-', t));
                }
                for (int j = 0; j < row.Count; j++)
                {
                    Debug.Write(PadRight(row[j], maxLength[j] + space));
                    Debug.Write("|");
                }
                Debug.WriteLine("");
            }
        }

        public static string Print(string self) {
            Debug.WriteLine(self ?? "null");
            return self;
        }

        public static void Print<T>(IEnumerable<T> self) {
            Debug.WriteLine("["+string.Join(",",self.Select(x=>x.ToString()).ToArray())+"]");
        }
        public static void Print<TKey, TValue>(IDictionary<TKey, TValue> self) {
            Debug.WriteLine("{" + string.Join(",", self.Select(x => x.Key+":"+x.Value).ToArray()) + "}");
        }
        public static void Print(DbCommand self) {
            Debug.WriteLine(FormatCommand(self));
        }

        static readonly Encoding encoding = Encoding.Default;

        /// <summary>
        /// 解决string#PadRight()中文字符串宽度问题
        /// 左对齐此字符串中的字符，在右边用paddingChar填充以达到指定的总长度
        /// </summary>
        /// <param name="str"></param>
        /// <param name="totalWidth"></param>
        /// <param name="paddingChar"></param>
        /// <returns></returns>
        private static string PadRight(string str, int totalWidth, char paddingChar)
        {
            int realLength = encoding.GetByteCount(str);
            return str.PadRight(totalWidth - (realLength - str.Length), paddingChar);
        }
        /// <summary>
        /// 解决string#PadRight()中文字符串宽度问题
        /// 左对齐此字符串中的字符，在右边用空格填充以达到指定的总长度。
        /// </summary>
        /// <param name="str"></param>
        /// <param name="totalWidth"></param>
        /// <returns></returns>
        private static string PadRight(string str, int totalWidth)
        {
            return PadRight(str, totalWidth, ' ');
        }

        /// <summary>
        /// 获取字符串宽度,1个中文为2,1个英文字母为1
        /// </summary>
        /// <param name="str"></param>
        /// <returns></returns>
        private static int GetLength(string str)
        {
            return encoding.GetByteCount(str);
        }
    }
}